/* poll_pipes.c

   Example of the use of poll() to monitor multiple file descriptors.

   Usage: poll_pipes num-pipes [num-writes]
                                  def = 1

   Create 'num-pipes' pipes, and perform 'num-writes' writes to
   randomly selected pipes. Then use poll() to inspect the read ends
   of the pipes to see which pipes are readable.
*/
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

static void errExit(char *msg) {
  perror(msg);
  exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
  int numPipes, ready, randPipe, numWrites, j;
  struct pollfd *pollFd;
  int(*pfds)[2]; /* File descriptors for all pipes */

  if (argc < 2 || strcmp(argv[1], "--help") == 0) {
    fprintf(stderr, "%s num-pipes [num-writes]\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  /* Allocate the arrays that we use. The arrays are sized according
     to the number of pipes specified on command line */
  numPipes = atoi(argv[1]);
  numWrites = (argc > 2) ? atoi(argv[2]) : 1;

  pfds = calloc(numPipes, sizeof(int[2]));
  if (pfds == NULL) errExit("calloc");
  pollFd = calloc(numPipes, sizeof(struct pollfd));
  if (pollFd == NULL) errExit("calloc");

  /* Create the number of pipes specified on command line */
  for (j = 0; j < numPipes; j++) {
    if (pipe(pfds[j]) == -1) {
      fprintf(stderr, "pipe %d", j);
      exit(EXIT_FAILURE);
    }
  }

  /* Perform specified number of writes to random pipes */
  srandom((int)time(NULL));
  for (j = 0; j < numWrites; j++) {
    randPipe = random() % numPipes;
    printf("Writing to fd: %3d (read fd: %3d)\n", pfds[randPipe][1],
           pfds[randPipe][0]);
    if (write(pfds[randPipe][1], "a", 1) == -1) {
      fprintf(stderr, "write %d", pfds[randPipe][1]);
      exit(EXIT_FAILURE);
    }
  }

  /* Build the file descriptor list to be supplied to poll(). This list
     is set to contain the file descriptors for the read ends of all of
     the pipes. */
  for (j = 0; j < numPipes; j++) {
    pollFd[j].fd = pfds[j][0];
    pollFd[j].events = POLLIN;
  }

  ready = poll(pollFd, numPipes, 0);
  if (ready == -1) errExit("poll");

  printf("poll() returned: %d\n", ready);
  /* Check which pipes have data available for reading */

  for (j = 0; j < numPipes; j++) {
    if (pollFd[j].revents & POLLIN) printf("Readable: %3d\n", pollFd[j].fd);
  }

  exit(EXIT_SUCCESS);
}